{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "socSJe925zFv"
   },
   "source": [
    "#  Molecular Fingerprints\n",
    "\n",
    "Molecules can be represented in many ways.  This tutorial introduces a type of representation called a \"molecular fingerprint\".  It is a very simple representation that often works well for small drug-like molecules.\n",
    "\n",
    "## Colab\n",
    "\n",
    "This tutorial and the rest in this sequence can be done in Google colab. If you'd like to open this notebook in colab, you can use the following link.\n",
    "\n",
    "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/deepchem/deepchem/blob/master/examples/tutorials/Molecular_Fingerprints.ipynb)\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 170
    },
    "colab_type": "code",
    "id": "CMWAv-Z46nCc",
    "outputId": "9ae7cfd0-ebbf-40b0-f6f1-2940cf32a839"
   },
   "outputs": [],
   "source": [
    "!pip install --pre deepchem"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "Jk47QTZ95zF-"
   },
   "source": [
    "We can now import the `deepchem` package to play with."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 35
    },
    "colab_type": "code",
    "id": "PDiY03h35zF_",
    "outputId": "cdd7401d-19a0-4476-9297-b04defc67178"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'2.4.0-rc1.dev'"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import deepchem as dc\n",
    "dc.__version__"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "B0u7qIZd5zGG"
   },
   "source": [
    "# What is a Fingerprint?\n",
    "\n",
    "Deep learning models almost always take arrays of numbers as their inputs.  If we want to process molecules with them, we somehow need to represent each molecule as one or more arrays of numbers.\n",
    "\n",
    "Many (but not all) types of models require their inputs to have a fixed size.  This can be a challenge for molecules, since different molecules have different numbers of atoms.  If we want to use these types of models, we somehow need to represent variable sized molecules with fixed sized arrays.\n",
    "\n",
    "Fingerprints are designed to address these problems.  A fingerprint is a fixed length array, where different elements indicate the presence of different features in the molecule.  If two molecules have similar fingerprints, that indicates they contain many of the same features, and therefore will likely have similar chemistry.\n",
    "\n",
    "DeepChem supports a particular type of fingerprint called an \"Extended Connectivity Fingerprint\", or \"ECFP\" for short.  They also are sometimes called \"circular fingerprints\".  The ECFP algorithm begins by classifying atoms based only on their direct properties and bonds.  Each unique pattern is a feature.  For example, \"carbon atom bonded to two hydrogens and two heavy atoms\" would be a feature, and a particular element of the fingerprint is set to 1 for any molecule that contains that feature.  It then iteratively identifies new features by looking at larger circular neighborhoods.  One specific feature bonded to two other specific features becomes a higher level feature, and the corresponding element is set for any molecule that contains it.  This continues for a fixed number of iterations, most often two.\n",
    "\n",
    "Let's take a look at a dataset that has been featurized with ECFP."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "saTaOpXY5zGI"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<DiskDataset X.shape: (6264, 1024), y.shape: (6264, 12), w.shape: (6264, 12), task_names: ['NR-AR' 'NR-AR-LBD' 'NR-AhR' ... 'SR-HSE' 'SR-MMP' 'SR-p53']>\n"
     ]
    }
   ],
   "source": [
    "tasks, datasets, transformers = dc.molnet.load_tox21(featurizer='ECFP')\n",
    "train_dataset, valid_dataset, test_dataset = datasets\n",
    "print(train_dataset)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "F922OPtL5zGM"
   },
   "source": [
    "The feature array `X` has shape (6264, 1024).  That means there are 6264 samples in the training set.  Each one is represented by a fingerprint of length 1024.  Also notice that the label array `y` has shape (6264, 12): this is a multitask dataset.  Tox21 contains information about the toxicity of molecules.  12 different assays were used to look for signs of toxicity.  The dataset records the results of all 12 assays, each as a different task.\n",
    "\n",
    "Let's also take a look at the weights array."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 102
    },
    "colab_type": "code",
    "id": "YEDcUsz35zGO",
    "outputId": "5a05747f-8b06-407d-9b11-790a1b4d1c8f"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1.0433141624730409, 1.0369942196531792, 8.53921568627451, ...,\n",
       "        1.060388945752303, 1.1895710249165168, 1.0700990099009902],\n",
       "       [1.0433141624730409, 1.0369942196531792, 1.1326397919375812, ...,\n",
       "        0.0, 1.1895710249165168, 1.0700990099009902],\n",
       "       [0.0, 0.0, 0.0, ..., 1.060388945752303, 0.0, 0.0],\n",
       "       ...,\n",
       "       [0.0, 0.0, 0.0, ..., 0.0, 0.0, 0.0],\n",
       "       [1.0433141624730409, 1.0369942196531792, 8.53921568627451, ...,\n",
       "        1.060388945752303, 0.0, 0.0],\n",
       "       [1.0433141624730409, 1.0369942196531792, 1.1326397919375812, ...,\n",
       "        1.060388945752303, 1.1895710249165168, 1.0700990099009902]],\n",
       "      dtype=object)"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "train_dataset.w"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "E8UCFrrN5zGf"
   },
   "source": [
    "Notice that some elements are 0.  The weights are being used to indicate missing data.  Not all assays were actually performed on every molecule.  Setting the weight for a sample or sample/task pair to 0 causes it to be ignored during fitting and evaluation.  It will have no effect on the loss function or other metrics.\n",
    "\n",
    "Most of the other weights are close to 1, but not exactly 1.  This is done to balance the overall weight of positive and negative samples on each task.  When training the model, we want each of the 12 tasks to contribute equally, and on each task we want to put equal weight on positive and negative samples.  Otherwise, the model might just learn that most of the training samples are non-toxic, and therefore become biased toward identifying other molecules as non-toxic.\n",
    "\n",
    "# Training a Model on Fingerprints\n",
    "\n",
    "Let's train a model.  In earlier tutorials we use `GraphConvModel`, which is a fairly complicated architecture that takes a complex set of inputs.  Because fingerprints are so simple, just a single fixed length array, we can use a much simpler type of model."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "e5K3rdGV5zGg"
   },
   "outputs": [],
   "source": [
    "model = dc.models.MultitaskClassifier(n_tasks=12, n_features=1024, layer_sizes=[1000])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "_Zcd7jTd5zGr"
   },
   "source": [
    "`MultitaskClassifier` is a simple stack of fully connected layers.  In this example we tell it to use a single hidden layer of width 1000.  We also tell it that each input will have 1024 features, and that it should produce predictions for 12 different tasks.\n",
    "\n",
    "Why not train a separate model for each task?  We could do that, but it turns out that training a single model for multiple tasks often works better.  We will see an example of that in a later tutorial.\n",
    "\n",
    "Let's train and evaluate the model."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 34
    },
    "colab_type": "code",
    "id": "LJc90fs_5zGs",
    "outputId": "8c9fd5ab-e23a-40dc-9292-8b4ff3a86890"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "training set score: {'roc_auc_score': 0.9550063590563469}\n",
      "test set score: {'roc_auc_score': 0.7781819573695475}\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "\n",
    "model.fit(train_dataset, nb_epoch=10)\n",
    "metric = dc.metrics.Metric(dc.metrics.roc_auc_score)\n",
    "print('training set score:', model.evaluate(train_dataset, [metric], transformers))\n",
    "print('test set score:', model.evaluate(test_dataset, [metric], transformers))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "aQa88cbj5zGw"
   },
   "source": [
    "Not bad performance for such a simple model and featurization.  More sophisticated models do slightly better on this dataset, but not enormously better."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "MhZxVoVs5zMa"
   },
   "source": [
    "# Congratulations! Time to join the Community!\n",
    "\n",
    "Congratulations on completing this tutorial notebook! If you enjoyed working through the tutorial, and want to continue working with DeepChem, we encourage you to finish the rest of the tutorials in this series. You can also help the DeepChem community in the following ways:\n",
    "\n",
    "## Star DeepChem on [GitHub](https://github.com/deepchem/deepchem)\n",
    "This helps build awareness of the DeepChem project and the tools for open source drug discovery that we're trying to build.\n",
    "\n",
    "## Join the DeepChem Gitter\n",
    "The DeepChem [Gitter](https://gitter.im/deepchem/Lobby) hosts a number of scientists, developers, and enthusiasts interested in deep learning for the life sciences. Join the conversation!"
   ]
  },
   {
      "cell_type": "markdown",
      "source": [
        "## Citing This Tutorial\n",
        "If you found this tutorial useful please consider citing it using the provided BibTeX. "
      ],
      "metadata": {
        "id": "pOBd6-YdQSvF"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "@manual{Intro4, \n",
        " title={Molecular Fingerprints}, \n",
        " organization={DeepChem},\n",
        " author={Ramsundar, Bharath}, \n",
        " howpublished = {\\url{https://github.com/deepchem/deepchem/blob/master/examples/tutorials/Molecular_Fingerprints.ipynb}}, \n",
        " year={2021}, \n",
        "} "
      ],
      "metadata": {
        "id": "KZUk_9yIYw0c"
      },
      "execution_count": null,
      "outputs": []
    }
 ],
 "metadata": {
  "colab": {
   "name": "01_The_Basic_Tools_of_the_Deep_Life_Sciences.ipynb",
   "provenance": []
  },
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
